import React, {FC, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState} from "react";
import "./css/ListPage.less";
import {Panel, PanelGroup, PanelResizeHandle} from "react-resizable-panels";
import GlobalIcon from "../../global/GlobalIcon.tsx";
import DetailsContent from "../../main/content/DetailsContent.tsx";
import GlobalBtn from "../../global/GlobalBtn.tsx";
import {configChange} from "../../Config.tsx";
import {formatStr, getObjByRule, isFunction, isString, strToObject} from "../../utils";
import useStateRef from "../../customUse/useStateRef.tsx";
import {loadMenuChild} from "../../services/MenuService.tsx";
import {coreDispatch} from "../../utils/StoreUtil.tsx";
import GlobalSearch from "../../global/GlobalSearch.tsx";
import CTable from "../../global/table/CTable.tsx";

let numberStep: number;

configChange((config: any) => {
    numberStep = config.numberStep;
});

/*
* 公共列表
* */
interface ListPageProps {
    key?: string | undefined,
    init: any,
    menu?: any[],
    menuId?: string,
    menuShowIcon?: boolean,
    menuClassName?: string,
    parentKey?: string | undefined,
    row?: any,
    leftRow?: any,
    viewName: string | any[],
    tableApi?: any,
    keywords?: string,
    dataSource?: [],
    drawerInfo: any,
    splitDirection: "horizontal" | "vertical",
    splitPage?: any,
    search?: string | undefined,
    rowKey?: string | undefined,
    pictureField?: string | undefined,
    rowHeight?: number | undefined,
    headerHeight?: number | undefined,
    rowSelection?: 'single' | 'multiple' | undefined,
    autoExpand?: boolean | undefined,
    isPagination?: boolean | undefined,
    isLazyData?: boolean | undefined,
    isSideBar?: boolean | undefined,
    hasCheckbox?: boolean | undefined,
    isInitSearch?: boolean | undefined,
    isShowBtn?: boolean | undefined,
    isShowHeader?: boolean | string,
    isTreeTable?: boolean | undefined,
    searchAutoExpand?: boolean | undefined,
    isParentLinkChild?: boolean | undefined,
    otherRenderFn?: Function,
    getRenderCardContent?: Function,
    searchData?: Function,
    otherDs?: any,
    dataSourceFilter?: Function | undefined,
    getLinkParams?: Function | undefined,
    getRenderContent?: Function | undefined,
    beforeSearch?: Function,
    onValuesChange?: Function,
    onSelectChange?: Function,
    method?: string,
    otherTableParams?: any,
    keepOtherAttr?: boolean,
    isFormatChild?: boolean,
    searchFn: any,
    defaultSize: any,
    copyType: any,
    isReloadObject: any,
    rowUrl: any
}

const ListPage: FC<ListPageProps> = (props) => {
    const {otherDs = {}} = props;

    const listRef: any = useRef();
    const searchRef: any = useRef();
    const btnRef: any = useRef();
    const cTable: any = useRef();
    const searchViewRef: any = useRef();
    const tableApiRef: any = useRef();
    const menusRef: any = useRef();
    const panelRef: any = useRef();

    const ds: any = {
        menuId: props.menuId,
        row: props.row || {},
        getRow: () => {
            return [props.row || []];
        },
        checkRows: () => {
            if (cTable.current && cTable.current) {
                return cTable.current.getTableSelectedRows();
            }
        },
        checkRow: () => {
            if (cTable.current && cTable.current) {
                return cTable.current.getTableSelectedRows()[0]
            }
        },
        reload: function (opt: any) {
            cTable.current.searchTable();
        },
        splitPage: function (opt: any) {
            setSplitPage({...opt, key: Math.random()});
        },
        closeSplitPage: function () {
            setSplitPage({})
        },
        ...otherDs
    };

    const [viewName, setViewName] = useState<string | any[]>(),
        [tableApi, setTableApi] = useStateRef(undefined, tableApiRef),
        [menus, setMenus] = useStateRef(null, menusRef),
        [splitPage, setSplitPage] = useState<any>({}),
        [splitDirection, setSplitDirection] = useState<"horizontal" | "vertical">(props.splitDirection || "vertical");

    const loadMenus: Function = useCallback(async () => {
        const {menuId, menu = []} = props;
        if (menuId) {
            const data = await loadMenuChild({parentId: menuId, menuType: "BUTTON"});
            coreDispatch("menuReducer/createMenuBtn", data);
            setMenus(data);
        } else if (menu) {
            setMenus(menu);
        }
    }, [props.menuId]);

    const searchData: Function = useCallback((searchParams: any = {}, isSearch: any) => {
        if (props.searchData) {
            props.searchData(searchParams, isSearch)
        } else {
            let {initParams = {}} = tableApiRef.current || {}
            cTable.current?.searchTable({...initParams, ...searchParams}, isSearch);
        }
    }, [tableApi, props.searchData]);

    const onSearchTable: Function = useCallback((params: any = {}) => {
        let newParams: any = {...params};
        if (props.beforeSearch) {
            newParams = props.beforeSearch(params, props);
        }
        searchData({...newParams, page: 1}, true)
    }, [tableApi, props.beforeSearch, props.search]);

    const onReset: Function = useCallback(() => {
        searchData({page: 1}, false)
    }, [tableApi]);

    const otherRenderFn: Function = useCallback(() => {
        if (props.otherRenderFn && isFunction(props.otherRenderFn)) {
            return props.otherRenderFn()
        }
        return {}
    }, [props.otherRenderFn]);

    const getRenderContent: Function = useCallback((cTable: any, height: number, tableApi: any) => {
        return props.getRenderContent && props.getRenderContent(cTable, height, tableApi);
    }, [props]);

    const initTableApi: Function = useCallback(() => {
        let {keepOtherAttr = false, isFormatChild = false} = props
        let newTableApi: any = {};
        if (props.tableApi) {
            newTableApi = {
                ...props.tableApi,
            }
            if (props.tableApi.initParams && isString(props.tableApi.initParams)) {
                newTableApi.initParams = strToObject(newTableApi.initParams);
            }
            if (props.tableApi.params) {
                newTableApi.params = getObjByRule(props, props.tableApi.params, keepOtherAttr, isFormatChild)
            }
        }
        setTableApi(newTableApi);
    }, [props.tableApi, props.row, props.leftRow, props.keywords]);

    const getTableHeight = useCallback(() => {
        if (!menusRef.current) {
            return 0
        }
        let listHeight: number = listRef.current?.clientHeight;
        if (Object.keys(splitPage).length && splitDirection === "vertical") {
            const sizePercen = 50
            listHeight = Math.floor((listHeight * sizePercen) / 100) - 12
        }
        const searchHeight: number = props.search ? (searchRef.current?.clientHeight || 70) : 0;
        let btnHeight: number = btnRef.current?.clientHeight;
        if (!btnHeight) {
            btnHeight = menusRef.current.length ? 36 : 0;
        }
        return listHeight - searchHeight - btnHeight;
    }, [props.search, splitDirection, splitPage]);

    useEffect(() => {
        if (!props.dataSource) {
            initTableApi();
        }
        setViewName(props.viewName);
    }, [props.tableApi, JSON.stringify(props.row), props.leftRow, props.keywords, props.viewName, props.dataSource]);

    useEffect(() => {
        loadMenus();
    }, [props.menuId]);

    useEffect(() => {
        setSplitPage(props.splitPage || {});
    }, [props.splitPage]);

    useImperativeHandle(props.init, () => {
        return {
            cTable: () => {
                return cTable.current;
            },
            getMenu: () => {
                return menus
            },
            refSetMenus: (menus: any[]) => {
                setMenus([...menus])
            },
            getSearchRef: () => {
                return searchViewRef
            },
            setSplitPage,
            getOtherDs: ds
        };
    });

    const renderSearch: any = useMemo(() => {
        const {search, menuId, onValuesChange}: {
            search?: string | undefined,
            menuId: string,
            onValuesChange?: Function
        } = props;
        if (!search) {
            return null;
        }
        return (<GlobalSearch
            init={searchViewRef}
            menuId={menuId}
            view={search}
            onSearch={onSearchTable}
            onReset={onReset}
            dataSource={ds}
            onValuesChange={onValuesChange}
        />);
    }, [props.search, tableApi, props.menuId]);

    const renderBtn: any = useMemo(() => {
        if (!menus || !menus.length) {
            return null;
        }
        return (<GlobalBtn
            menus={menus}
            dataSource={ds}
            isShowIcon={props.menuShowIcon}
            className={props.menuClassName}
        />);
    }, [menus, props.menuShowIcon, props.menuClassName, props.row]);

    const renderTable: any = useMemo(() => {
        const {
            key,
            rowKey = "id",
            pictureField = "id",
            menuId,
            parentKey = "parentId",
            drawerInfo,
            dataSource,
            rowHeight = 30,
            headerHeight = 30,
            hasCheckbox = true,
            autoExpand,
            searchAutoExpand,
            isPagination = false,
            isLazyData = false,
            isTreeTable = false,
            isAddVirtual = false,
            isSideBar = true,
            isShowHeader = "keyword",
            isInitSearch = true,
            rowSelection = 'multiple',
            isParentLinkChild = false,
            dataSourceFilter,
            onSelectChange,
            getLinkParams,
            isRowSelectable,
            getRenderCardContent,
            getRowStyle,
            otherTableParams,
            searchFn,
            copyType = 'Item',
            isReloadObject,
            rowUrl,
            boxCheck = false
        }:
            {
                key?: string | undefined,
                rowKey?: string | undefined,
                pictureField?: string | undefined,
                menuId?: string | undefined,
                parentKey?: string | undefined,
                drawerInfo: any,
                dataSource?: any[],
                rowHeight?: number | undefined,
                headerHeight?: number | undefined,
                rowSelection?: 'single' | 'multiple' | undefined,
                searchAutoExpand?: boolean | undefined,
                autoExpand?: boolean | undefined,
                isPagination?: boolean | undefined,
                isLazyData?: boolean | undefined,
                isSideBar?: boolean | undefined,
                isShowHeader?: boolean | string,
                isInitSearch?: boolean | undefined,
                hasCheckbox?: boolean | undefined,
                isTreeTable?: boolean | undefined,
                isAddVirtual?: boolean | undefined,
                isParentLinkChild?: boolean | undefined,
                dataSourceFilter?: Function | undefined,
                onSelectChange?: Function | undefined,
                getLinkParams?: Function | undefined,
                isRowSelectable?: Function | undefined,
                getRenderCardContent?: Function | undefined,
                getRowStyle?: Function | undefined,
                otherTableParams?: any,
                searchFn?: any,
                copyType: any,
                isReloadObject: any,
                rowUrl: any,
                boxCheck?: any
            } = props;
        if (!tableApi && !dataSource) {
            return null;
        }
        let tableHeight = getTableHeight();
        let renderOtherTable: any = getRenderContent(cTable, tableHeight, tableApi);
        if (renderOtherTable) {
            return renderOtherTable;
        }
        if (!viewName) {
            return null;
        }
        let Com = CTable;
        return (
            <Com
                init={cTable}
                menuId={menuId}
                searchFn={searchFn}
                isInitSearch={isInitSearch}
                key={key}
                pictureField={pictureField}
                drawerInfo={drawerInfo}
                getLinkParams={getLinkParams}
                view={viewName}
                tableApi={tableApi}
                rowKey={isAddVirtual ? "tableVirtualId" : rowKey}
                dataSource={dataSource}
                parentKey={parentKey}
                autoExpand={autoExpand}
                searchAutoExpand={searchAutoExpand}
                height={tableHeight}
                headerHeight={headerHeight}
                rowHeight={rowHeight}
                rowSelection={rowSelection}
                hasCheckbox={hasCheckbox}
                otherRenderFn={otherRenderFn()}
                getRenderCardContent={getRenderCardContent}
                isParentLinkChild={isParentLinkChild}
                isTreeTable={isTreeTable}
                isLazyData={isLazyData}
                isSideBar={isSideBar}
                isShowHeader={isShowHeader}
                isPagination={isPagination}
                isAddVirtual={isAddVirtual}
                dataSourceFilter={dataSourceFilter}
                onSelectChange={onSelectChange}
                isRowSelectable={isRowSelectable}
                getRowStyle={getRowStyle}
                ds={ds}
                otherTableParams={otherTableParams}
                copyType={copyType}
                isReloadObject={isReloadObject}
                rowUrl={rowUrl}
                boxCheck={boxCheck}
            />
        )
    }, [menus, tableApi, props.isShowBtn, props.key, props.rowKey, props.pictureField, props.menuId, props.parentKey, viewName, props.hasCheckbox, props.otherTableParams, props.getRenderCardContent, props.getLinkParams, props.onSelectChange, props.dataSourceFilter, props.isParentLinkChild, props.isTreeTable, props.isInitSearch, props.isSideBar, props.isLazyData, props.isPagination, props.autoExpand, props.rowSelection, props.headerHeight, props.rowHeight, props.drawerInfo, props.dataSource, splitDirection, splitPage]);

    const renderVirtual: any = useMemo(() => {
        let {objectId, objectTypeId}: {
            objectId: string,
            objectTypeId: string
        } = splitPage;
        if (!objectTypeId) {
            return null
        }
        objectId = formatStr(objectId, ds.row);
        return (
            <DetailsContent {...splitPage} objectId={objectId} objectTypeId={objectTypeId} ds={ds}/>
        )
    }, [splitPage, splitDirection]);

    const renderListPage = useMemo(() => {
        const {isShowBtn = true} = props;
        return (
            <div className={"sf_core_list_page"}>
                <div style={{height: '100%'}} ref={listRef}>
                    <PanelGroup direction={splitDirection} className="sf_core_list_page_box"
                                style={{height: "100%"}}>
                        <Panel className='sf_core_list_page_box_left' ref={panelRef}>
                            <div ref={searchRef}>
                                {renderSearch}
                            </div>
                            <div ref={btnRef}>
                                {isShowBtn ? renderBtn : null}
                            </div>
                            {renderTable}
                        </Panel>
                        {Object.keys(splitPage).length ?
                            <>
                                <PanelResizeHandle/>
                                <Panel className="sf_core_list_page_box_right"
                                       defaultSize={props.defaultSize || 50}>
                                    <div className="sf_core_list_page_box_right_close">
                                        <GlobalIcon
                                            name={splitDirection == "horizontal" ? "icon-left-split-right" : "icon-top-split-bottom"}
                                            onClick={() => {
                                                setSplitDirection(splitDirection == "horizontal" ? "vertical" : "horizontal")
                                                setSplitPage({...splitPage, key: Math.random()})
                                            }}/>
                                        <GlobalIcon name={"icon-close-page"} onClick={() => {
                                            setSplitPage({})
                                        }}/>
                                    </div>
                                    {renderVirtual}
                                </Panel>
                            </> : null}
                    </PanelGroup>
                </div>
            </div>
        )
    }, [props, viewName, tableApi, menus, splitPage, splitDirection]);

    return (renderListPage);
};

export default React.memo(ListPage);